#pragma once

#include <iostream>
#include <unordered_set>
#include <unordered_map>
#include <functional>
#include <unistd.h>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "LogMessage.hpp"
#include "ExistReason.hpp"
#include "ThreadPool.hpp"
#include "LocalGuard.hpp"
#include "Pthread.hpp"
#include "InetAddr.hpp"

using task_t = std::function<void()>;

std::unordered_set<std::string> forbid = {
    "rm",
    "mv",
    "kill",
    "cp"};

class ChatServer
{
public:
    ChatServer(const uint16_t &port, const std::string &str = "")
    {
        // 创建套接字
        _socket = socket(AF_INET, SOCK_DGRAM, 0);
        if (_socket < 0)
        {
            Log::LogMessage(Error, "create socket error");
            exit(CREATE_SOCKET_ERROR);
        }
        Log::LogMessage(Debug, "create socket success, socket: %d", _socket);

        // 进行bind
        sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(port);
        addr.sin_addr.s_addr = str.empty() ? INADDR_ANY : inet_addr(str.c_str());

        int n = bind(_socket, (sockaddr *)&addr, sizeof(addr));
        if (n < 0)
        {
            Log::LogMessage(Error, "bind error");
            exit(BIND_ERROR);
        }
        Log::LogMessage(Debug, "bind success");

        pthread_mutex_init(&_user_mutex, nullptr);
        ThreadPool<task_t>::GetInstance()->Start();
    }

    ~ChatServer()
    {
        pthread_mutex_destroy(&_user_mutex);
        close(_socket);
    }

    void Start()
    {
        while (true)
        {
            // 回显客户端消息即可
            NectChat();
        }
    }

private:
    void AddUser(InetAddr &user)
    {
        LockGuard lock(&_user_mutex);
        std::string userMessage = user.GetUser();
        if (_users.find(userMessage) != _users.end())
        {
            return;
        }
        _users.insert({userMessage, user});
    }

    void Route(size_t sock, std::string message)
    {
        //将message发送给每一个用户
        LockGuard lock(&_user_mutex);
        for (auto user : _users)
        {
            sockaddr_in addr = user.second.GetAddr();
            sendto(sock, message.c_str(), message.size(), 0, (sockaddr*)&addr, sizeof(addr));
        }
    }

    void DebugPrint()
    {
        for (auto user : _users)
        {
            std::cout << user.first << std::endl;
        }
    }

    void NectChat()
    {
        while (true)
        {
            char temp[1024];
            sockaddr_in addr;
            memset(&addr, 0, sizeof(addr));
            socklen_t addrlen = sizeof(addr);
            int n = recvfrom(_socket, temp, sizeof(temp) - 1, 0, (sockaddr *)&addr, &addrlen);
            temp[n] = 0;

            InetAddr user(addr);
            if (n > 0)
            {
                // 将用户信息保存起来
                AddUser(user);
                std::string message = "[";
                message += user.GetUser();
                message += "] ";
                message += temp;

                // 将任务push到队列当中
                task_t task = std::bind(&ChatServer::Route, this, _socket, message);
                ThreadPool<task_t>::GetInstance()->Push(task);
            }
            else if (n == 0)
            {
                // 对端关闭连接
                Log::LogMessage(Debug, "close connection");
            }
            else
            {
                Log::LogMessage(Warning, "server recvfrom warning");
            }
        }
    }

private:
    int _socket;
    std::unordered_map<std::string, InetAddr> _users;
    pthread_mutex_t _user_mutex;
};